﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Reflection;
using JsStubGenerator;

namespace UIT.Web
{
    public class JStubHandler : IHttpHandler
    {
        #region IHttpHandler Members

        public bool IsReusable
        {
            get { return true; }
        }

        private static IDictionary<string, string> generatedAssemlyCache = new Dictionary<string, string>();

        public void ProcessRequest(HttpContext context)
        {
            string requestedDll = Path.GetFileNameWithoutExtension(context.Request.RawUrl);
            string renderedDll;
            JsStubVisibility defaultVisibility = JsStubVisibility.Hidden;
            if (!generatedAssemlyCache.TryGetValue(requestedDll, out renderedDll))
            {
                lock (generatedAssemlyCache)
                {
                    Assembly requestedAssembly = PageHandler.references.FirstOrDefault(assembly => assembly.GetName().Name == requestedDll);
                    var retrievedAttributes = requestedAssembly.GetCustomAttributes(typeof(ExposeTypeAttribute), true);
                    ExposeTypeAttribute[] attributes = new ExposeTypeAttribute[retrievedAttributes.Length];
                    retrievedAttributes.CopyTo(attributes, 0);
                    ExposeTypeAttribute defaultBehavior = attributes.FirstOrDefault(att => att.Type == null);
                    NamespaceFragment root = new NamespaceFragment();
                    if (defaultBehavior != null)
                        defaultVisibility = defaultBehavior.Visibility;
                    if (defaultVisibility == JsStubVisibility.Exposed)
                    {
                        foreach (Type t in requestedAssembly.GetExportedTypes())
                        {
                            ExposeTypeAttribute attribute = attributes.FirstOrDefault(att => att.Type == t);
                            if (attribute != null && attribute.Visibility == JsStubVisibility.Hidden)
                                continue;
                            retrievedAttributes = t.GetCustomAttributes(typeof(ExposeTypeAttribute), true);
                            if (retrievedAttributes.Length != 0 && ((ExposeTypeAttribute)retrievedAttributes[0]).Visibility == JsStubVisibility.Hidden)
                                continue;
                            root.Register(t.Namespace, t);
                        }
                    }
                    else
                    {
                        foreach (ExposeTypeAttribute attribute in attributes)
                        {
                            if (attribute.Type == null)
                                continue;
                            root.Register(attribute.Type.Namespace, attribute.Type);
                        }

                        foreach (Type t in requestedAssembly.GetExportedTypes())
                        {
                            retrievedAttributes = t.GetCustomAttributes(typeof(ExposeTypeAttribute), true);
                            if (retrievedAttributes.Length != 0 && ((ExposeTypeAttribute)retrievedAttributes[0]).Visibility == JsStubVisibility.Exposed)
                                root.Register(t.Namespace, t);
                        }
                    }
                    StringBuilder sb = new StringBuilder();
                    root.Render(new StringWriter(sb), true);
                    renderedDll = sb.ToString();
                    generatedAssemlyCache.Add(requestedDll, renderedDll);
                }
            }

            context.Response.ContentType = "type/javascript";
            context.Response.Write(renderedDll);
        }

        #endregion
    }
}
